/*
Hermes Core: General Purpose Mobile Agent Platform
Copyright (C) 2006 UNICAM - Università degli Studi di Camerino

Group leaders: Flavio Corradini and Emanuela Merelli

Developers: Ezio Bartocci, Diego Bonura, Rosario Culmone,
Davide Lorenzoli, Leonardo Mariani, Francesca Piersigilli, 
Lorenzo Scortichini, Leonardo Vito.

GNU Lesser Public License

This library is free software; you can redistribute it 
and/or modify it under the terms of the GNU Lesser General 
Public License as published by the Free Software Foundation, 
version 2.1 of the License.

This library is distributed in the hope that it will be useful, 
but WITHOUT ANY WARRANTY; without even the implied warranty of 
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
See the GNU Library General Public License for more details.

You should have received a copy of the GNU Library General Public 
License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.

Emanuela Merelli
Dipartimento di Matematica ed Informatica
Università di Camerino
via Madonna delle Carceri, 62032 Camerino, Italy
E.Mail: emanuela.merelli@unicam.it
*/
package hermesV2.agent;

import hermesV2.util.HermesLogger;

import java.io.Serializable;
import java.util.Hashtable;

/**
 * @author Diego Vito
 * @author Leonardo Vito
 * @author Ezio Bartocci (Porting in Java 1.5)
 * 
 * AbstractProtocol rappresents a generic protocol between agents.
 * It stores Interaction instances and links them to each other.
 * Gives to the user all the facilites to make protocols easy and well-formed. 
 *  
 */
public abstract class AbstractProtocol implements Serializable {

    /**
	 * 
	 */
	private static final long serialVersionUID = 8251895424560112081L;

	/**
     * Contains all the interactions of the protocol.
     */
    private Hashtable<String, Interaction> interactions;
    
    /**
     * Contains links between an interaction and its well response.
     */
    private Hashtable<String, String>  responseLink;
    /**
     * Contains links between an interaction and its error response.
     */
    private Hashtable<String, String>  errorLinks;
    /**
     * The name of the protocol.
     */
    private String protocolName; 
    
    /**
     * The constructor of the AbstractProtocol.
     * @param protocolName The name of the protocol.
     */
    public AbstractProtocol(String protocolName){
        this.interactions = new Hashtable<String, Interaction>();
        this.responseLink = new Hashtable<String, String> ();
        this.errorLinks = new Hashtable<String, String> ();
        this.protocolName = protocolName;
    }
    
    
    /**
     * Adds a new interaction to the current protocol.
     * If the interaction is present into the protocol it overwrite the old one.
     * 
     * @param interactionName The name of the interaction.
     * @param interactionType The type of the interaction.
     * @param interactionAction The action associated to the interaction.
     * @param interactionParameterNames The array of the all parameters name of the interaction.
     * @param interactionParameterTypes The array of the all parameters type of the interaction.
     * +
     * 
     *
     */
    final protected void addInteraction(String interactionName, String interactionType, String interactionAction, String[] interactionParameterNames, Class<?>[] interactionParameterTypes) {
        if (interactionParameterNames.length == interactionParameterTypes.length) {
            Interaction i = new Interaction(interactionName, interactionType, interactionAction, interactionParameterNames, interactionParameterTypes);
            interactions.put(interactionName, i);
        } else {
            HermesLogger.log(HermesLogger.WARNING,"Protocol Error");
        }
    }

    /**
     * Adds a new interaction to the current protocol without parameters.
     * If the interaction is present into the protocol it overwrite the old one.
     * @param interactionName The name of the interaction.
     * @param interactionType The type of the interaction.
     * @param interactionAction The action associated to the interaction.
     */
    final protected void addInteraction(String interactionName, String interactionType, String interactionAction) {
        Interaction i = new Interaction(interactionName, interactionType, interactionAction);
        interactions.put(interactionName, i);
    }
    
    
    /**
     * Return the interaction with a specific name.
     * @param interactionName The name of the interaction to search.
     * @return The interaction instance or null.
     */
    final protected Interaction getInteraction(String interactionName) {
    	return interactions.get(interactionName);
    }
    
    /**
     * Return the interaction with a specific name.
     * @return The interaction instance or null.
     */
    final protected Interaction[] getAllInteractions() {
    	return interactions.values().toArray(new Interaction[interactions.values().size()]);
    }

    /**
     * Adds a new interaction to the current protocol.
     * If the interaction is present into the protocol it overwrite the old one.
     * @param interaction The interaction to add.
    */
   
    final protected void addInteraction(Interaction interaction) {
        interactions.put(interaction.getName(), interaction);
    }
    
    /**
     * Add a new link between two interaction already set.
     * @param nameRequest The name of the first interaction.
     * @param nameResponse The name of the response interaction.
     */
    final protected void addResponseLink(String nameRequest,String nameResponse){
        responseLink.put(nameRequest,nameResponse);
    }
    
    /**
     * Add a new link between two interaction already set.
     * @param interactionRequest The first interaction reference.
     * @param interactionResponse The reference of the response interaction.
     */
    final protected void addResponseLink(Interaction interactionRequest,Interaction interactionResponse){
        responseLink.put(interactionRequest.getName(),interactionResponse.getName());
    }
    
    /**
     * Add a new error link between two interaction already set.
     * @param nameRequest The name of the first interaction.
     * @param nameResponse The name of the error response interaction.
     */
    final protected void addErrorLink(String nameRequest,String nameResponse){
        errorLinks.put(nameRequest,nameResponse);
    }
    
    /**
     * Add a new error link between two interaction already set.
     * @param interactionRequest The first interaction reference.
     * @param interactionResponse The reference of the response interaction.
     */
    final protected void addErrorLink(Interaction interactionRequest,Interaction interactionResponse){
        errorLinks.put(interactionRequest.getName(),interactionResponse.getName());
    }
    
    
    /**
     * Return the interaction linked to the interaction gave.
     * @param interaction The interaction.
     * @return The linked interacton.
     */
    final protected Interaction getResponseInteractionLink(Interaction interaction){
               return this.getInteraction(responseLink.get(interaction.getName()));
    }
    
    /**
     * Return the interaction linked to the interaction name gave.
     * @param interactionName The interaction.
     * @return The linked interacton.
     */
    final protected Interaction getResponseInteractionLink(String interactionName){
        return this.getInteraction(responseLink.get(interactionName));
}
    /**
     * Return the error interaction linked to the interaction gave.
     * @param interaction The interaction.
     * @return The linked interacton.
     */
    final protected Interaction getErrorInteractionLink(Interaction interaction){
        return this.getInteraction(errorLinks.get(interaction.getName()));
    }
    
    /**
     * Return the error interaction linked to the interaction name gave.
     * @param interactionName The interaction.
     * @return The linked interacton.
     */
    final protected Interaction getErrorInteractionLink(String interactionName){
        return this.getInteraction(errorLinks.get(interactionName));
    }

    /**
     * @return Returns the protocolName.
     */
    final public String getName() {
        return protocolName;
    }
}